package com.hucsmn.authentication;

import java.io.*;
import java.net.*;

/**
 * 用户信息认证客户端。
 */
public class AuthClient {
    /**
     * 默认连接地址 127.0.0.1。
     */
    public static final InetAddress ADDRESS = Inet4Address.getLoopbackAddress();

    /**
     * 默认连接端口 8888。
     */
    public static final int PORT = 8888;

    /**
     * 套接字超时时间。
     */
    private static final int TIMEOUT = 10000;

    // 连接地址。
    private InetAddress address;
    private int port;

    /**
     * 设置认证客户端，连接默认地址和端口号。
     */
    AuthClient() {
        this(ADDRESS, PORT);
    }

    /**
     * 设置认证客户端，连接默认地址和指定端口号。
     *
     * @param port 认证服务器端口号。
     */
    AuthClient(int port) {
        this(ADDRESS, port);
    }

    /**
     * 设置认证客户端，连接指定地址和端口号。
     *
     * @param address 认证服务器地址。
     * @param port 认证服务器端口号。
     */
    AuthClient(InetAddress address, int port) {
        setAddress(address);
        setPort(port);
    }

    /**
     * 连接认证服务器，并等待服务器返回消息，确认用户登录信息是否正确。
     *
     * @param user 用户登录信息。
     * @return 用户登录信息是否正确。
     * @throws IOException 连接错误或者数据编码异常。
     */
    public boolean authenticate(User user) throws IOException {
        if (user == null) {
            throw new NullPointerException();
        }

        try (Socket sock = new Socket()) {
            sock.connect(new InetSocketAddress(address, port), TIMEOUT);
            sock.setSoTimeout(TIMEOUT);

            ObjectOutputStream out = new ObjectOutputStream(sock.getOutputStream());
            out.writeObject(new UserMessage(UserMessage.CHECK, user));
            out.flush();

            ObjectInputStream in = new ObjectInputStream(sock.getInputStream());
            Object obj = in.readObject();
            if (!(obj instanceof UserMessage)) {
                throw new ClassCastException();
            }
            UserMessage um = (UserMessage) obj;
            if (!um.validate() || UserMessage.CHECK.equals(um.getType())) {
                throw new InvalidObjectException("not a valid user message response");
            }

            return UserMessage.SUCCESS.equals(um.getType());
        } catch (ClassNotFoundException | ClassCastException e) {
            throw new InvalidObjectException("not a user message object");
        }
    }

    /**
     * 获取认证服务器地址。
     *
     * @return 认证服务器地址。
     */
    public InetAddress getAddress() {
        return address;
    }

    /**
     * 设置认证服务器地址。
     *
     * @param address 认证服务器地址。
     */
    private void setAddress(InetAddress address) {
        if (address == null) {
            throw new NullPointerException();
        }
        this.address = address;
    }

    /**
     * 获取认证服务器端口。
     *
     * @return 认证服务器端口。
     */
    public int getPort() {
        return port;
    }

    /**
     * 设置认证服务器端口。
     *
     * @param port 认证服务器端口。
     */
    private void setPort(int port) {
        if (port <= 0) {
            throw new IllegalArgumentException();
        }
        this.port = port;
    }
}
